package zhh.tangbao.user.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import zhh.tangbao.system.constant.CommonConstant;
import zhh.tangbao.system.constant.DataStatus;
import zhh.tangbao.system.dto.BaseEntityUpdateDto;
import zhh.tangbao.system.entity.PagerEntity;
import zhh.tangbao.system.exception.ReEntryException;
import zhh.tangbao.system.exception.ServiceException;
import zhh.tangbao.system.utils.HttpServletRequestUtil;
import zhh.tangbao.system.utils.UserHolderUtil;
import zhh.tangbao.system.utils.ZhhStringUtil;
import zhh.tangbao.user.cache.UserCache;
import zhh.tangbao.user.dao.AuthorityDao;
import zhh.tangbao.user.dao.UserDao;
import zhh.tangbao.user.dto.*;
import zhh.tangbao.user.entity.User;
import zhh.tangbao.user.service.RoleService;
import zhh.tangbao.user.service.UserService;
import zhh.tangbao.user.vo.*;
import zhh.tangbao.wechat.dao.WeChatUserDao;
import zhh.tangbao.wechat.entity.WeChatUser;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * @author 粥灰灰
 * @created 2022/8/20
 * @version 1.0
 * @Description 服务实现层
 */

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao dao;

    @Resource
    private AuthorityDao authorityDao;

    @Autowired
    private UserHolderUtil userHolderUtil;

    @Autowired
    private UserCache userCache;

    @Autowired
    private WeChatUserDao weChatUserDao;

    @Autowired
    private RoleService roleService;

    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);


    @Override
    public UserVo getUserVo(String userId) {
        try {
            // 获取基础信息
            UserVo userVo = this.dao.getUserInfoById(userId);
            Assert.notNull(userVo, "未找到对应用户");
            Set<String> authorities = this.authorityDao.listAuthorities(userVo.getRoleId());
            userVo.setAuthorities(authorities);
            return userVo;
        } catch (Exception e) {
            log.error("zhh.tangbao.user.service.impl.UserServiceImpl.getUserVo: {}", e.getMessage());
            throw new ServiceException(e.getMessage());
        }
    }

    @Override
    public AuthorityVo userLogin(UserLoginDto dto) {
        // 因为UserVo不暴露密码，所以单独封装对象来校验密码正确与否
        UserLoginVo loginUser = this.dao.getUserLoginInfoByUserAccount(dto.getUserAccount());
        Assert.notNull(loginUser, "该用户不存在");
        if (userCache.inBlacklist(dto.getUserAccount())) {
            throw new ServiceException("该账号已被禁用");
        }
        // 不使用sql直接查询符合账号与密码的用户，防止sql注入
        if (dto.getPassword().equals(loginUser.getPassword())) {
            UserVo vo = getUserVo(loginUser.getId());
            String encryptKey = ZhhStringUtil.randomString16();
            String token = userCache.generateToken(vo.getId(), encryptKey);
            userCache.login(vo, token);
            userHolderUtil.setCurrentUser(vo);
            return new AuthorityVo().setAuthorities(vo.getAuthorities()).setToken(token).setKey(encryptKey).setUserName(vo.getUserName()).setUserAvatar(vo.getUserAvatar());
        } else {
            throw new ServiceException("密码错误");
        }
    }

    @Override
    @Transactional
    public int addUser(UserDto dto) {
        UserLoginVo userExist = dao.getUserLoginInfoByUserAccount(dto.getUserAccount());
        Assert.isNull(userExist, "该账号已被注册");
        UserVo currentLoginUser = userHolderUtil.getCurrentUser();
        User user = new User();
        BeanUtils.copyProperties(dto, user);
        user.setBaseCreateInfo(currentLoginUser.getId());
        return dao.insertUser(user);
    }

    @Override
    @Transactional
    public int deleteUser(long id) {
        return dao.deleteUserById(id);
    }

    @Override
    @Transactional
    public int updateUser(UserDto dto) {
        UserVo currentUser = userHolderUtil.getCurrentUser();
        User user = new User();
        BeanUtils.copyProperties(dto, user);
        user.setUpdateInfo(currentUser.getId());
        userCache.updateUser(getUserVo(dto.getId()));
        return dao.updateUser(user);
    }

    @Override
    @Transactional
    public int updatePassword(UserPasswordDto dto) {
        UserVo currentUser = userHolderUtil.getCurrentUser();
        UserLoginVo loginVo = dao.getUserLoginInfoByUserAccount(currentUser.getUserAccount());
        Assert.notNull(loginVo, "未查询到该账号");
        if (!dto.getOldPassword().equals(loginVo.getPassword())) {
            throw new ServiceException("原密码不正确，请重新输入");
        }
        User user = new User();
        user.setPassword(dto.getNewPassword());
        user.setId(currentUser.getId());
        user.setUpdateInfo(currentUser.getId());
        return dao.updateUser(user);
    }

    @Override
    public boolean userExist(String account) {
        UserLoginVo exist = dao.getUserLoginInfoByUserAccount(account);
        return null != exist;
    }

    @Override
    public void logout() {
        String token = HttpServletRequestUtil.getRequestHeader(CommonConstant.TOKEN);
        String tk = HttpServletRequestUtil.getRequestHeader(CommonConstant.TOKEN_KEY);
        userCache.logout(token, tk);
    }

    @Override
    public int addReplenishment(String id) {
        WeChatUser weChatUser = weChatUserDao.selectOne(new QueryWrapper<WeChatUser>().eq("id", id));
        Assert.notNull(weChatUser, "该账号不存在，无法设置补货权限");
        weChatUser.setIsReplenishment(1);
        return weChatUserDao.updateById(weChatUser);
    }

    @Override
    public int cancelReplenishment(String phone) {
        WeChatUser weChatUser = weChatUserDao.selectOne(new QueryWrapper<WeChatUser>().eq("phone_number", phone));
        Assert.notNull(weChatUser, "该账号不存在，无法设置补货权限");
        weChatUser.setIsReplenishment(0);
        return weChatUserDao.updateById(weChatUser);
    }

    @Override
    public Page<WeChatUser> wechatUserPage(WeChatUserDto dto) {
        Page<WeChatUser> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        QueryWrapper<WeChatUser> wrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(dto.getPhone())) {
            wrapper.eq("phone_number", dto.getPhone());
        }
        if (null != dto.getReplenishment()) {
            wrapper.eq("is_replenishment", dto.getReplenishment());
        }
        return weChatUserDao.selectPage(page, wrapper);
    }

    @Override
    public boolean isOnline() {
        UserVo currentUser = userHolderUtil.getCurrentUser();
        if (null == currentUser) {
            throw new ReEntryException("登录信息已过期");
        }
        return true;
    }


    @Override
    public PagerEntity<UserPageVo> page(PagerEntity<UserPageVo> pager, UserDto dto) {
        List<UserPageVo> result = dao.listUserPageVo(pager, dto);
        if (CollUtil.isEmpty(result)) {
            return pager;
        }
        result.forEach(r -> {
            String userAccount = r.getUserAccount();
            if (userCache.inBlacklist(userAccount)) {
                long remainingBanTime = userCache.getRemainingBanTime(userAccount);
                Date target = new Date(System.currentTimeMillis() + remainingBanTime);
                userCache.getRemainingBanTime(userAccount);
                r.setBan(true);
                r.setUnBanTime(target);
            }
        });
        long count = dao.count(dto);
        pager.setData(result);
        pager.setTotalNum(count);
        return pager;
    }

    @Override
    public void banUser(UserBannedDto dto) {
        String currentAccount = userHolderUtil.getCurrentUser().getUserAccount();
        String userAccount = dto.getUserAccount();
        if (currentAccount.equals(userAccount)) {
            throw new ServiceException("本人无法禁用本人账号");
        }
        userCache.banUser(dto.getUserAccount(), dto.getTime());
    }

    @Override
    public void unBanUser(UserBannedDto dto) {
        userCache.unBanUser(dto.getUserAccount());
    }

    @Override
    public int addAdmin(UserDto dto) {
        UserLoginVo userExist = dao.getUserLoginInfoByUserAccount(dto.getUserAccount());
        Assert.isNull(userExist, "该账号已被注册");
        UserVo currentLoginUser = userHolderUtil.getCurrentUser();
        User user = new User();
        BeanUtils.copyProperties(dto, user);
        // 没有角色ID则视为通过注册功能增加的普通用户
        if (null == dto.getRoleId()) {
            String defaultRoleId = roleService.getDefaultRoleId(CommonConstant.ROLE_TYPE_ADMIN);
            user.setRoleId(defaultRoleId);
        }
        if (StrUtil.isBlank(dto.getUserName())) {
            user.setUserName("默认管理员");
        }
        if (null == dto.getGender()) {
            user.setGender(0);
        }
        user.setEnableInfo(currentLoginUser.getId());
        return dao.insertUser(user);
    }

    @Override
    public UserDetailInfoVo getUserDetailInfo(String id) {
        UserDetailInfoVo userDetailInfo = dao.getUserDetailInfo(id);
        Assert.notNull(userDetailInfo, "用户不存在");
        return userDetailInfo;
    }

    @Override
    public int batchDeleteUser(List<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            throw new ServiceException("未选择用户");
        }
        String currentUserId = userHolderUtil.getCurrentUser().getId();
        if (ids.contains(currentUserId)) {
            throw new ServiceException("无法强制删除本人账号");
        }
        return dao.batchDeleteUserByIds(ids, new BaseEntityUpdateDto(currentUserId, new Date(), DataStatus.DELETED));
    }
}
